#ifndef _SAMPLER_H_
#define _SAMPLER_H_

#include <memory>
#include <cassert>

typedef struct  
{
	float image_x,image_y;
}camera_sample_t;

inline bool operator<(const camera_sample_t& lhs, const camera_sample_t& rhs)
{
	return (lhs.image_x < rhs.image_x) || !(rhs.image_x < lhs.image_x) && (lhs.image_y < rhs.image_y);
}

inline bool operator>(const camera_sample_t& lhs, const camera_sample_t& rhs)
{
	return rhs<lhs;
}
inline bool operator<=(const camera_sample_t& lhs, const camera_sample_t& rhs)
{
	return !(lhs>rhs);
}
inline bool operator>=(const camera_sample_t& lhs, const camera_sample_t& rhs)
{
	return !(lhs<rhs);
}
inline bool operator==(const camera_sample_t& lhs, const camera_sample_t& rhs)
{
	return !(lhs<rhs) && !(rhs < lhs);
}

//camera sample generator
class Sampler
{
public:
	Sampler(int x_start,int x_end,
		int y_start,int y_end,int spp):x_pixel_start_(x_start),
		x_pixel_end_(x_end),y_pixel_start_(y_start),y_pixel_end_(y_end),
		samples_per_pixel_(spp){}
	virtual bool GetNextSample(camera_sample_t* cam_samp)=0;
	virtual void ResetSamplePosition() = 0;
	virtual size_t GetTotalSampleCount() = 0;
	virtual std::shared_ptr<Sampler> GetSubSampler(int i, int count) = 0;
	virtual ~Sampler(){}
protected:
	void ComputeSubWindow(int num, int count, int *x0,int *x1, int* y0, int *y1);
protected:
	int x_pixel_start_,x_pixel_end_;
	int y_pixel_start_,y_pixel_end_;
	int samples_per_pixel_;
private:
};

inline void Sampler::ComputeSubWindow(int num, int count, int *x0,int *x1, int* y0, int *y1)
{
	int dx = x_pixel_end_ - x_pixel_start_;
	int dy = y_pixel_end_ - y_pixel_start_;
	int nx = count, ny = 1;
	while((nx & 0x01) == 0 && 2 * dx * ny < dy * nx)
	{ 
		nx >>= 1;
		ny <<= 1;
	}
	assert(nx * ny == count);
	int xo = num % nx, yo = num / nx;
	float tx0 = float(xo) / float(nx), tx1 = float(xo+1)/ float(nx);
	float ty0 = float(yo) / float(ny), ty1 = float(yo+1)/float(ny);
	*x0 = (int)floorf(x_pixel_end_ * tx0 + (1-tx0) * x_pixel_start_);
	*x1 = (int)floorf(x_pixel_end_ * tx1 + (1-tx1) * x_pixel_start_);
	*y0 = (int)floorf(y_pixel_end_ * ty0 + (1-ty0) * y_pixel_start_);
	*y1 = (int)floorf(y_pixel_end_ * ty1 + (1-ty1) * y_pixel_start_);
}
#endif